package dao

import (
	"bytes"
	"context"
	"errors"
	"github.com/aws/aws-sdk-go/service/s3"
	"github.com/ecodeclub/ekit"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"strconv"
	"time"
)

type ArticleS3Dao struct {
	ArticleORMDAO
	oss    *s3.S3
	bucket *string
}

func NewArticleS3Dao(db *gorm.DB, client *s3.S3) *ArticleS3Dao {
	return &ArticleS3Dao{
		ArticleORMDAO: ArticleORMDAO{db: db}, oss: client,
		bucket: ekit.ToPtr[string]("webook-1314583317"),
	}
}
func (a *ArticleS3Dao) Sync(ctx context.Context, artn Article) (int64, error) {
	var id = artn.Id
	var err error
	err = a.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		dao := NewArticleORMDAO(tx) //使用事务实现创建我自己
		if id > 0 {
			err = dao.UpdateById(ctx, artn)
		} else {
			id, err = dao.Insert(ctx, artn)
		}
		if err != nil {
			return err
		}
		artn.Id = id
		now := time.Now().UnixMilli()
		pubArt := PublishedArticleV2{
			Id:       artn.Id,
			Title:    artn.Title,
			AuthorId: artn.AuthorId,
			Ctime:    now,
			Utime:    now,
			Status:   artn.Status,
		}
		pubArt.Ctime = now
		pubArt.Utime = now
		err = tx.Clauses(clause.OnConflict{
			Columns: []clause.Column{{Name: "id"}}, //对mysql不起效 可以兼容别的方言
			//INSERT XXX ON DUPLICATE KEY SET `title`=?
			//别的方言 sqlite INSERT XXX ON CONFLICT DO UPDATES
			//冲突了更新什么
			DoUpdates: clause.Assignments(map[string]interface{}{
				"title": pubArt.Title,
				//"content": pubArt.Content,
				"utime":  now,
				"status": pubArt.Status,
			}),
		}).Create(&pubArt).Error
		return err
	})
	//同步数据到oss
	_, err = a.oss.PutObjectWithContext(ctx, &s3.PutObjectInput{
		Bucket:      a.bucket,
		Key:         ekit.ToPtr[string](strconv.FormatInt(artn.Id, 10)),
		Body:        bytes.NewReader([]byte(artn.Content)),
		ContentType: ekit.ToPtr[string]("text/plain;charset=utf-8"),
	})
	return id, err
}
func (a *ArticleS3Dao) SyncStatus(ctx context.Context, uid int64, id int64, status uint8) error {
	now := time.Now().UnixMilli()
	err := a.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		res := tx.Model(&Article{}).Where("id = ? and author_id = ?", id, uid).
			Updates(map[string]any{
				"utime":  now,
				"status": status,
			})
		if res.Error != nil {
			return res.Error
		}
		if res.RowsAffected != 1 {
			return errors.New("更新数据失败 ID不对或创作者不对")
		}
		return tx.Model(&PublishedArticleV2{}).Where("id = ?", id).
			Updates(map[string]any{
				"utime":  now,
				"status": status,
			}).Error
	})
	if err != nil {
		return err
	}
	const statusPrivate = 3
	//要从oss里删除
	//问题：如果使用oss和cdn ，oss删除了，cdn里可能还有缓存
	if status == statusPrivate {
		_, err = a.oss.DeleteObjectWithContext(ctx, &s3.DeleteObjectInput{
			Bucket: a.bucket,
			Key:    ekit.ToPtr[string](strconv.FormatInt(id, 10)),
		})
	}
	return err
}

type PublishedArticleV2 struct {
	Id    int64  `gorm:"primaryKey,autoIncrement" bson:"id,omitempty"`
	Title string `gorm:"type=varchar(4096)" bson:"title,omitempty"`
	//Content string `gorm:"type=BLOB" bson:"content,omitempty"`
	//根据创作者ID来查询
	AuthorId int64 `gorm:"index" bson:"author_id,omitempty"`
	Status   uint8 `bson:"status,omitempty"`
	Ctime    int64 `bson:"ctime,omitempty"`
	Utime    int64 `bson:"utime,omitempty"`
}
